Working with the kernel (Back End)

We can know 'where we are' using the following:

In [ ]:
%connect_info

Now I can open a qtconsole connected to the same kernel:

ipython qtconsole --existing kernel-6ea34ea1-9b11-441d-9f7a-693c1cf71804.json

And I can modify what I have in the notebook from the console and viceversa

In [ ]:
a = 3
In [ ]:
assert a == 3

Creating our own kernels

This recipe was shamelessly stolen from the [excellent cookbook](http://ipython-books.github.io/cookbook/) written by [@cyrillerossant](https://twitter.com/cyrillerossant).

Let's create a very simple and minimal kernel that will add a modification of the python print function in the notebook.

In [ ]:
%%writefile printkernel.py

from io import StringIO

from IPython.kernel.zmq.kernelbase import Kernel
from IPython.display import HTML

a = '<p style="font-size:20px;background-color:black;color:yellow;">&gt;&gt;&gt;&nbsp;'
b = '</p>'

class PrintKernel(Kernel):
    implementation = 'Print'
    implementation_version = '-31.0'
    language = 'python'  # will be used for
                         # syntax highlighting
    language_version = ''
    banner = "Advanced printing in the notebook"
    
    def do_execute(self, code, silent,
                   store_history=True,
                   user_expressions=None,
                   allow_stdin=False):

        expr = None
        try:
            expr = code.split('print(')[1].split(')')[0]
            out = HTML(a + eval(expr) + b)
        except:
            pass

        if not silent:
            if expr:
                # We send the standard output to the client.
                self.send_response(self.iopub_socket,
                    'stream', {
                        'name': 'stdout', 
                        'data': 'Richer print'})

                # We prepare the response with our rich data
                # (the plot).
                content = {"html": [out.data],
                        "metadata": {},
                        "text": [repr(out)]}

                # We send the display_data message with the
                # contents.
                self.send_response(self.iopub_socket,
                    'display_data', content)

        # We return the exection results.
        return {'status': 'ok',
                'execution_count': self.execution_count,
                'payload': [],
                'user_expressions': {},
               }

if __name__ == '__main__':
    from IPython.kernel.zmq.kernelapp import IPKernelApp
    IPKernelApp.launch_instance(kernel_class=PrintKernel)

My dumb kernel is here. The next step is to indicate to IPython that this new kernel is available. To do this, we need to create a kernel spec kernel.json file and put it in (IPYTHONDIR)/kernels/print/. This file contains the following lines:

{
 "argv": ["python", "-m",
          "printkernel", "-f",
          "{connection_file}"],
 "display_name": "Print",
 "language": "python"
}

Let's see how the kernel works. Run the following in a console from the same folder where printkernel.py and kernel.json files are:

ipython notebook --KernelManager.kernel_cmd="['python', '-m', 'printkernel', '-f', '{connection_file}']"

Go deeper